﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.Windows.UserControls.Core.Extentions;
using Microsoft.Windows.UserControls.ViewModels;

namespace Microsoft.Windows.UserControls
{
    [TemplatePart(Name = "PART_ContentPresenter", Type = typeof(ContentPresenter))]
    [TemplatePart(Name = "PART_PageHeader", Type = typeof(Border))]
    [TemplatePart(Name = "PART_PageIndex", Type = typeof(Border))]
    [TemplatePart(Name = "PART_PageNavigation", Type = typeof(Border))]
    public class WizardPage : ContentControl
    {
        #region  Dependency Properties
        
        #region PageHeader

        public static readonly DependencyProperty PageHeaderBackgroundProperty = DependencyProperty.Register("PageHeaderBackground", typeof(Brush), typeof(WizardPage));
        
        public static readonly DependencyProperty PageHeaderTitleProperty = DependencyProperty.Register("PageHeaderTitle", typeof(string), typeof(WizardPage));
        
        public static readonly DependencyProperty PageHeaderDescriptionProperty = DependencyProperty.Register("PageHeaderDescription", typeof(string), typeof(WizardPage));
        
        public static readonly DependencyProperty PageHeaderImageProperty = DependencyProperty.Register("PageHeaderImage", typeof(ImageSource), typeof(WizardPage));
        
        #endregion
        
        #region PageIndex
        
        public static readonly DependencyProperty PageIndexBackgroundProperty = DependencyProperty.Register("PageIndexBackground", typeof(Brush), typeof(WizardPage));
        
        public static readonly DependencyProperty PageIndexContentProperty = DependencyProperty.Register("PageIndexContent", typeof(object), typeof(WizardPage), new UIPropertyMetadata(null, PageIndexContentPropertyChanged  ));
       
        public static readonly DependencyProperty PageIndexVisibilityProperty = DependencyProperty.Register("PageIndexVisibility", typeof(Visibility), typeof(WizardPage), new PropertyMetadata(Visibility.Collapsed));
       
        #endregion
        
        #region PageNavigation 
        
        public static readonly DependencyProperty PageNavigationBackgroundProperty = DependencyProperty.Register("PageNavigationBackground", typeof(Brush), typeof(WizardPage));
        
        #endregion

        #region Page
        
        public static readonly DependencyProperty PageTypeProperty = DependencyProperty.Register("PageType", typeof(WizardPageType), typeof(WizardPage), new UIPropertyMetadata(WizardPageType.Normal));
        
        #endregion
        
        public static readonly DependencyProperty AllowHelpExecuteCommandProperty = DependencyProperty.Register("AllowHelpExecuteCommand", typeof(Boolean), typeof(WizardPage), new PropertyMetadata(OnAllowHelpExecuteCommandPropertyChanged));
        
        public static readonly DependencyProperty AllowPreviousExecuteCommandProperty = DependencyProperty.Register("AllowPreviousExecuteCommand", typeof(Boolean), typeof(WizardPage), new PropertyMetadata(OnAllowPreviousExecuteCommandPropertyChanged));
        
        public static readonly DependencyProperty AllowNextExecuteCommandProperty = DependencyProperty.Register("AllowNextExecuteCommand", typeof(Boolean), typeof(WizardPage), new PropertyMetadata(OnAllowNextExecuteCommandPropertyChanged));
        
        public static readonly DependencyProperty AllowCancelExecuteCommandProperty = DependencyProperty.Register("AllowCancelExecuteCommand", typeof(Boolean), typeof(WizardPage), new PropertyMetadata(OnAllowCancelExecuteCommandPropertyChanged));
        
        public static readonly DependencyProperty AllowFinishExecuteCommandProperty = DependencyProperty.Register("AllowFinishExecuteCommand", typeof(Boolean), typeof(WizardPage), new PropertyMetadata(OnAllowFinishExecuteCommandPropertyChanged));
        
        public static readonly DependencyProperty OwnerProperty = DependencyProperty.Register("Owner", typeof(Wizard), typeof(WizardPage), new UIPropertyMetadata(null));
        
        #endregion
        
        #region Properties
       
        #region PageHeader
        
        public Brush PageHeaderBackground
        {
            get
            {
                return (Brush)base.GetValue(PageHeaderBackgroundProperty);
            }
            set
            {
                base.SetValue(PageHeaderBackgroundProperty, value);
            }
        }
        
        public String PageHeaderTitle
        {
            get
            {
                return (String)base.GetValue(PageHeaderTitleProperty);
            }
            set
            {
                base.SetValue(PageHeaderTitleProperty, value);
            }
        }
        
        public String PageHeaderDescription
        {
            get
            {
                return (String)base.GetValue(PageHeaderDescriptionProperty);
            }
            set
            {
                base.SetValue(PageHeaderDescriptionProperty, value);
            }
        }
        
        public ImageSource PageHeaderImage
        {
            get
            {
                return (ImageSource)base.GetValue(PageHeaderImageProperty);
            }
            set
            {
                base.SetValue(PageHeaderImageProperty, value);
            }
        }
        
        #endregion
       
        #region PageIndex
        
        public Brush PageIndexBackground
        {
            get
            {
                return (Brush)base.GetValue(PageIndexBackgroundProperty);
            }
            set
            {
                base.SetValue(PageIndexBackgroundProperty, value);
            }
        }
        
        public object PageIndexContent
        {
            get
            {
                return base.GetValue(PageIndexContentProperty);
            }
            set
            {
                base.SetValue(PageIndexContentProperty, value);
            }
        }

        public Visibility PageIndexVisibility
        {
            get
            {
                return (Visibility)base.GetValue(PageIndexVisibilityProperty);
            }
            set
            {
                base.SetValue(PageIndexVisibilityProperty, value);
            }
        }
        #endregion
        
        #region PageNavigation 
        
        public Brush PageNavigationBackground
        {
            get
            {
                return (Brush)base.GetValue(PageNavigationBackgroundProperty);
            }
            set
            {
                base.SetValue(PageNavigationBackgroundProperty, value);
            }
        }
        
        #endregion
         
        public Boolean AllowHelpExecuteCommand
        {
            get
            {
                return (Boolean)base.GetValue(AllowHelpExecuteCommandProperty);
            }
            set
            {
                base.SetValue(AllowHelpExecuteCommandProperty, value);
            }
        }
        
        public Boolean AllowPreviousExecuteCommand
        {
            get
            {
                return (Boolean)base.GetValue(AllowPreviousExecuteCommandProperty);
            }
            set
            {
                base.SetValue(AllowPreviousExecuteCommandProperty, value);
            }
        }
        
        public Boolean AllowNextExecuteCommand
        {
            get
            {
                return (Boolean)base.GetValue(AllowNextExecuteCommandProperty);
            }
            set
            {
                base.SetValue(AllowNextExecuteCommandProperty, value);
            }
        }
        
        public Boolean AllowCancelExecuteCommand
        {
            get
            {
                return (Boolean)base.GetValue(AllowCancelExecuteCommandProperty);
            }
            set
            {
                base.SetValue(AllowCancelExecuteCommandProperty, value);
            }
        }
        
        public Boolean AllowFinishExecuteCommand
        {
            get
            {
                return (Boolean)base.GetValue(AllowFinishExecuteCommandProperty);
            }
            set
            {
                base.SetValue(AllowFinishExecuteCommandProperty, value);
            }
        }
        
        public WizardPageType PageType
        {
            get
            {
                return (WizardPageType)base.GetValue(PageTypeProperty);
            }
            set
            {
                base.SetValue(PageTypeProperty, value);
            }
        }
        
        internal Wizard Owner
        {
            get
            {
                var owner = (Wizard)base.GetValue(OwnerProperty);
                if (owner == null)
                    base.SetValue(OwnerProperty, this.ParentOfType<Wizard>());
                return (Wizard)base.GetValue(OwnerProperty);
            }
            set
            {
                base.SetValue(OwnerProperty, value);
            }
        }
        
        #endregion 
        
        ContentPresenter partContentPresenter;
        Border partPageHeader;
        Border partPageIndex;
        Border partPageNavigation;
        
        #region ctor
        
        static WizardPage()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(WizardPage), new FrameworkPropertyMetadata(typeof(WizardPage)));
        }
        
        public WizardPage()
        {
            this.Loaded += OnWizardPageLoaded;
        }
        
        #endregion
        
        #region static Methods
        
        static void PageIndexContentPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            var control = sender as WizardPage;
            if (control == null)
                return;

            control.PageIndexVisibility = args.NewValue == null? Visibility.Collapsed: Visibility.Visible;
           
        }

        static void OnAllowHelpExecuteCommandPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            if (SenderIsWizardPageValid(sender))
                ((WizardPage)sender).Owner.SetCanExecuteHelpCommand();
        }
        
        static void OnAllowPreviousExecuteCommandPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            if (SenderIsWizardPageValid(sender))
                ((WizardPage)sender).Owner.SetCanExecutePreviousCommand();
        }
        
        static void OnAllowNextExecuteCommandPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            if (SenderIsWizardPageValid(sender))
                ((WizardPage)sender).Owner.SetCanExecuteNextCommand();
        }
        
        static void OnAllowCancelExecuteCommandPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            if (SenderIsWizardPageValid(sender))
                ((WizardPage)sender).Owner.SetCanExecuteCancelCommand();
        }
        
        static void OnAllowFinishExecuteCommandPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            if (SenderIsWizardPageValid(sender))
                ((WizardPage)sender).Owner.SetCanExecuteFinishCommand();
        }
        
        static Boolean SenderIsWizardPageValid(DependencyObject sender)
        {
            var control = (sender as WizardPage);
            if (control == null)
                return false;
                
            if (control.Owner == null)
                return false;
                
            if (control.Owner.CurrentPage == null)
                return false;
                
            if (control.Owner.CurrentPage.Name != control.Name)
                return false;
        
            return true;
        }
        
        #endregion
        
        #region Events
        
        void OnWizardPageLoaded(object sender, RoutedEventArgs e)
        {
            PropagateDataContext();
            base.DataContextChanged += OnWizardPageDataContextChanged;
            if (Owner != null)
                Owner.OnWizardPageLoaded(this);
        }

        void OnWizardPageDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            PropagateDataContext();
        }
        
        #endregion
        
        #region Overrides
        
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            partContentPresenter = GetTemplateChild("PART_ContentPresenter") as ContentPresenter;
            partPageHeader = GetTemplateChild("PART_PageHeader") as Border;
            partPageIndex = GetTemplateChild("PART_PageIndex") as Border;
            partPageNavigation = GetTemplateChild("PART_PageNavigation") as Border;
        }
        
        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
            if ((IWizardPageViewModel)DataContext == null )
                DataContext = new WizardPageViewModelBase( PageHeaderTitle, PageHeaderDescription);
            ((IWizardPageViewModel)DataContext).Type = PageType;
            SetBindings();
        }
        
        protected virtual void SetBindings()
        {
            SetBinding(AllowHelpExecuteCommandProperty, "Navigation.Help.IsEnabled");
            SetBinding(AllowPreviousExecuteCommandProperty, "Navigation.Previous.IsEnabled");
            SetBinding(AllowNextExecuteCommandProperty, "Navigation.Next.IsEnabled");
            SetBinding(AllowCancelExecuteCommandProperty, "Navigation.Cancel.IsEnabled");
            SetBinding(AllowFinishExecuteCommandProperty, "Navigation.Finish.IsEnabled");
        }
        
        protected virtual void PropagateDataContext()
        {
            if (partContentPresenter != null)
                partContentPresenter.DataContext = base.DataContext;
            
            if (partPageHeader != null)
                partPageHeader.DataContext = base.DataContext;
            
            if (partPageIndex != null)
                partPageIndex.DataContext = base.DataContext;
            
            if (partPageNavigation != null)
                partPageNavigation.DataContext = base.DataContext;
        }

        #endregion
        
        public override string ToString()
        {
            return String.Format("{0} {1}", this.GetType().FullName, this.Name);
        }
        
        public enum WizardPageType
        {
            Normal,
            Welcome,
            Completion
        }
    }
}